package com.sgcc.pda.util;

import android.content.ContentValues;
import android.database.Cursor;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据转换工具类.
 *
 * @author 王沛栋
 * @data 2018/1/19 16:55
 */

public class DataConversionUtil {
    private static final char UNDERLINE='_';//定义驼峰转移字符

    /**
     * 实体类转换成ContentValues
     * <p>此方法适用于存储Sharepreference的存储</p>
     * <p>有三种分类类型  int  String 和boolean类型</p>
     * <p>int类型用于数据分类</P>
     * @param obj
     * @return
     */
    public static ContentValues BeanToContentValues(Object obj){
        ContentValues values = new ContentValues();

        Class cls = obj.getClass();
        Field[] fields = cls.getDeclaredFields();
        for(int i=0; i<fields.length; i++){
            Field f = fields[i];
            f.setAccessible(true);
            try {
//                LogUtil.e("shuchu","属性名:" + f.getName() +
//                        " :属性值:" + f.get(obj)+":属性类型"+
//                        f.getGenericType().toString());

//                属性名:editorKey :属性值:simcard_sn:属性类型class java.lang.String
//                属性名:value :属性值:testSimId:属性类型class java.lang.String
//                属性名:key :属性值:simcard_snNo:属性类型class java.lang.String
//                属性名:type :属性值:0:属性类型int
//                属性名:editorMode :属性值:0:属性类型int

//                Type type =  f.getGenericType();

                if(null == f.get(obj)){
                    continue;
                }

                String type = f.getGenericType().toString().toLowerCase();

                if (type.contains("string")){
                    values.put(f.getName(), f.get(obj).toString());
                }else if (type.contains("int")){
                    values.put(f.getName(), Integer.parseInt(f.get(obj).toString()));
                }else if(type.contains("boolean")){
                    boolean b = (boolean) f.get(obj);
                    if(b){
                        values.put(f.getName(), "1");
                    }else{
                        values.put(f.getName(), "0");
                    }
                }else{
                    values.put(f.getName(), f.get(obj).toString());
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return values;
    }




    /**
     * 驼峰转下划线
     * @param param
     * @return
     */
    public static String camelToUnderline(String param){
        if (param==null||"".equals(param.trim())){
            return "";
        }
        int len=param.length();
        StringBuilder sb=new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c=param.charAt(i);
            if (Character.isUpperCase(c)){
                sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            }else{
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 下划线转驼峰
     * @param param
     * @return
     */
    public static String underlineToCamel(String param){
        if (param==null||"".equals(param.trim())){
            return "";
        }
        int len=param.length();
        StringBuilder sb=new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c=param.charAt(i);
            if (c==UNDERLINE){
                if (++i<len){
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            }else{
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 下划线转驼峰
     * @param param
     * @return
     */
    public static String underlineToCamel2(String param){
        if (param==null||"".equals(param.trim())){
            return "";
        }
        StringBuilder sb=new StringBuilder(param);
        Matcher mc= Pattern.compile("_").matcher(param);
        int i=0;
        while (mc.find()){
            int position=mc.end()-(i++);
            //String.valueOf(Character.toUpperCase(sb.charAt(position)));
            sb.replace(position-1,position+1,sb.substring(position,position+1).toUpperCase());
        }
        return sb.toString();
    }



    /**
     * 字符串转换成十六进制字符串
     * @param str 待转换的ASCII字符串
     * @return String 每个Byte之间空格分隔，如: [61 6C 6B]
     */
    public static String str2HexStr(String str){

        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;

        for (int i = 0; i < bs.length; i++){
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
//            sb.append(' ');
        }
        return sb.toString().trim();
    }

    /**
     * 十六进制转换字符串
     * @param hexStr Byte字符串(Byte之间无分隔符 如:[616C6B])
     * @return String 对应的字符串
     */
    public static String hexStr2Str(String hexStr){
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;

        for (int i = 0; i < bytes.length; i++){
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }

    /**
     * bytes转换成十六进制字符串
     * @param b byte数组
     * @return String 每个Byte值之间空格分隔
     */
    public static String byte2HexStr(byte[] b){
        String stmp;
        StringBuilder sb = new StringBuilder("");
        for (int n=0;n<b.length;n++){
            stmp = Integer.toHexString(b[n] & 0xFF);
            sb.append((stmp.length()==1)? "0"+stmp : stmp);
            sb.append(" ");
        }
        return sb.toString().toUpperCase().trim();
    }

    /**
     * bytes字符串转换为Byte值
     * @param src Byte字符串，每个Byte之间没有分隔符
     * @return byte[]
     */
    public static byte[] hexStr2Bytes(String src){
        int m,n;
        int l=src.length()/2;
        System.out.println(l);
        byte[] ret = new byte[l];
        for (int i = 0; i < l; i++){
            m=i*2+1;
            n=m+1;
            ret[i] = Byte.decode("0x" + src.substring(i*2, m) + src.substring(m,n));
        }
        return ret;
    }

    /**
     * String的字符串转换成unicode的String
     * @param strText 全角字符串
     * @return String 每个unicode之间无分隔符
     */
    public static String strToUnicode(String strText)
            throws Exception {
        char c;
        StringBuilder str = new StringBuilder();
        int intAsc;
        String strHex;
        for (int i = 0; i < strText.length(); i++){
            c = strText.charAt(i);
            intAsc = (int) c;
            strHex = Integer.toHexString(intAsc);
            if (intAsc > 128)
                str.append("\\u" + strHex);
            else // 低位在前面补00
                str.append("\\u00" + strHex);
        }
        return str.toString();
    }

    /**
     * unicode的String转换成String的字符串
     * @param hex 16进制值字符串 （一个unicode为2byte）
     * @return String 全角字符串
     */
    public static String unicodeToString(String hex){
        int t = hex.length() / 6;
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < t; i++){
            String s = hex.substring(i * 6, (i + 1) * 6);
            // 高位需要补上00再转
            String s1 = s.substring(2, 4) + "00";
            // 低位直接转
            String s2 = s.substring(4);
            // 将16进制的string转为int
            int n = Integer.valueOf(s1, 16) + Integer.valueOf(s2, 16);
            // 将int转换为字符
            char[] chars = Character.toChars(n);
            str.append(new String(chars));
        }
        return str.toString();
    }


    /**
     * 获取指定长度的字符串
     *
     * @param oldString 转化之前字符串
     * @param length    长度
     * @return 固定长度的字符串
     */
    public static String getString(String oldString, int length) {
        StringBuilder stringBuffer = new StringBuilder();
        for (int i = 0; i < length - oldString.length(); i++) {
            stringBuffer.append("0");
        }
        stringBuffer.append(oldString);
        return stringBuffer.toString();
    }


    /**
     * 将HEX数组转换为中文字符
     *
     * @param hexString HEX数组
     * @return 中文字符
     */
    public static String hexStringToChinese(String hexString) {
        byte[] hexBytes = toBytes(hexString);

        // unicode 需要两个字节一组,出现单字节时需要补位
        if (hexBytes != null && hexBytes.length % 2 != 0) {
            byte[] byte_end = new byte[]{0x00};
            hexBytes = mergeArray(hexBytes, byte_end);
        }
        try {
            return new String(hexBytes, 0, hexBytes.length, "UnicodeLittleUnmarked").trim();
        } catch (Exception ex) {
            return "";
        }
    }

    /**
     * 将两个byte[] 合并,
     *
     * @param bytes
     * @param byte_end
     * @return bytes + byte_end 的结果
     */
    private static byte[] mergeArray(byte[] bytes, byte[] byte_end) {

        int byteLen1 = bytes.length;
        int byteLen2 = byte_end.length;
        bytes = Arrays.copyOf(bytes, byteLen1 + byteLen2);//扩容
        System.arraycopy(byte_end, 0, bytes, byteLen1, byteLen2);
        return bytes;
    }

    /**
     * 将16进制字符串转换成byte数组
     *
     * @param value 待转换字符串
     * @return 转换完成的字符串-正确 null-错误
     */
    private static byte[] toBytes(String value) {
        // 确保传入数据有效
        if (value == null || value.trim().length() <= 0) {
            return null;
        }
        value = value.trim();
        // 确保有效数据长度有效（为2的倍数）
        if (value.length() % 2 != 0) {
            return null;
        }
        byte[] ret = new byte[value.length() / 2];
        for (int i = 0; i < ret.length; i++) {
            try {
                /*
                前面的逻辑已经保证了字符串长度是byte数组长度的2倍
                这里没有进行数组越界的判断
                 */
                String tmp = value.substring(i * 2, i * 2 + 2);
                int a = Integer.parseInt(tmp, 16);
                int b = a & 0xFF;
                byte c = (byte) b;
                ret[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
            } catch (Exception e) {
                return null;
            }
        }
        return ret;
    }


    /**
     * Cursor对象转数据集合
     *
     * @param c
     * @param clazz
     * @return
     */
    public static List cursor2VOList(Cursor c, Class clazz) {
        if (c == null) {
            return null;
        }
        List list = new LinkedList();
        Object obj;
        try {
            while (c.moveToNext()) {
                obj = setValues2Fields(c, clazz);

                list.add(obj);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("ERROR @：cursor2VOList");
            return null;
        } finally {
            c.close();
        }
    }

    private static Object setValues2Fields(Cursor c, Class clazz)
            throws Exception {
        String[] columnNames = c.getColumnNames();// 字段数组
        //init a instance from the VO`s class
        Object obj = clazz.newInstance();
        //return a field array from obj`s ALL(include private exclude inherite(from father)) field
        Field[] fields = clazz.getDeclaredFields();

        for (Field _field : fields) {
            //field`s type
            Class<? extends Object> typeClass = _field.getType();// 属性类型
            for (int j = 0; j < columnNames.length; j++) {
                String columnName = columnNames[j];
                typeClass = getBasicClass(typeClass);
                //if typeclass is basic class ,package.if not,no change
                boolean isBasicType = isBasicType(typeClass);

                if (isBasicType) {
                    if (columnName.equalsIgnoreCase(_field.getName())) {// 是基本类型
                        String _str = c.getString(c.getColumnIndex(columnName));
                        if (_str == null) {
                            break;
                        }
                        _str = _str == null ? "" : _str;
                        //if value is null,make it to ""
                        //use the constructor to init a attribute instance by the value
                        Constructor<? extends Object> cons = typeClass
                                .getConstructor(String.class);
                        Object attribute = cons.newInstance(_str);
                        _field.setAccessible(true);
                        //give the obj the attr
                        _field.set(obj, attribute);
                        break;
                    }
                } else {
                    Object obj2 = setValues2Fields(c, typeClass);// 递归
                    _field.set(obj, obj2);
                    break;
                }

            }
        }
        return obj;
    }


    /**
     * 判断是不是基本类型
     *
     * @param typeClass
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static boolean isBasicType(Class typeClass) {
        if (typeClass.equals(Integer.class) || typeClass.equals(Long.class)
                || typeClass.equals(Float.class)
                || typeClass.equals(Double.class)
                || typeClass.equals(Boolean.class)
                || typeClass.equals(Byte.class)
                || typeClass.equals(Short.class)
                || typeClass.equals(String.class)) {

            return true;

        } else {
            return false;
        }
    }

    /**
     * 获得包装类
     *
     * @param typeClass
     * @return
     */
    @SuppressWarnings("all")
    public static Class<? extends Object> getBasicClass(Class typeClass) {
        Class _class = basicMap.get(typeClass);
        if (_class == null)
            _class = typeClass;
        return _class;
    }

    @SuppressWarnings("rawtypes")
    public static Map<Class, Class> basicMap = new HashMap<Class, Class>();

    static {
        basicMap.put(int.class, Integer.class);
        basicMap.put(long.class, Long.class);
        basicMap.put(float.class, Float.class);
        basicMap.put(double.class, Double.class);
        basicMap.put(boolean.class, Boolean.class);
        basicMap.put(byte.class, Byte.class);
        basicMap.put(short.class, Short.class);
    }

}
